這次作品的靈感是來自這個dribbble
CodePen:
https://codepen.io/zyrxdkoz/pen/dyRWKZM
clock部分
色彩模式切換
讓我們來看程式碼(值得特別注意的地方會加上備註):
Html部分
<!DOCTYPE html>
// 會在html加上dark選擇器
<html lang="en">
  <head>
    // 略
  </head>
  <body>
    <button class="toggle">Dark mode</button>
    <div class="clock-container">
    // 就跟真正的時鐘一樣有不同的元件。
      <div class="clock">
        <div class="needle hour"></div>
        <div class="needle minute"></div>
        <div class="needle second"></div>
        <div class="center-point"></div>
      </div>
      <div class="time"></div>
      <div class="date"></div>
    </div>
    <script src="script.js"></script>
  </body>
</html>
CSS部分 (節錄部分)
:root {
  --primary-color: #000;
  --secondary-color: #fff;
}
html {
  transition: all 0.5s ease-in;
}
html.dark {
  --primary-color: #fff;
  --secondary-color: #333;
  background-color: #111;
  color: var(--primary-color);
}
.clock-container {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
}
.clock {
  position: relative;
  width: 200px;
  height: 200px;
}
.needle {
  background-color: var(--primary-color);
  position: absolute;
  top: 50%;
  left: 50%;
  height: 65px;
  width: 3px;
  // 設定元素變化的原點:底部中間位置
  transform-origin: bottom center;
  transition: all 0.5s ease-in;
}
// 運用trasform屬性控制指針的定位和旋轉行為
.needle.hour {
  transform: translate(-50%, -100%) rotate(0deg);
}
.needle.minute {
  transform: translate(-50%, -100%) rotate(0deg);
  height: 100px;
}
.needle.second {
  transform: translate(-50%, -100%) rotate(0deg);
  height: 100px;
  background-color: #e74c3c;
}
// 指針中心
.center-point {
  background-color: #e74c3c;
  width: 10px;
  height: 10px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
}
// 用偽元素做出時鐘的中心部件(會依照色彩模式變換顏色)
.center-point::after {
  content: '';
  background-color: var(--primary-color);
  width: 5px;
  height: 5px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
}
Javascript部分
const hourEl = document.querySelector('.hour')
const minuteEl = document.querySelector('.minute')
const secondEl = document.querySelector('.second')
const timeEl = document.querySelector('.time')
const dateEl = document.querySelector('.date')
const toggle = document.querySelector('.toggle')
const days = [
  'Sunday',
  // 略
]
const months = [
  'Jan',
  // 略
  'Dec',
]
// 白天/夜晚模式切換,單純用classList的remove、add來實現
toggle.addEventListener('click', (e) => {
  const html = document.querySelector('html')
  if (html.classList.contains('dark')) {
    html.classList.remove('dark')
    e.target.innerHTML = 'Dark mode'
  } else {
    html.classList.add('dark')
    e.target.innerHTML = 'Light mode'
  }
})
// 這個函式可以在一個範圍內劃定要跑的階數。
const scale = (num, in_min, in_max, out_min, out_max) => {
  return ((num - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
}
function setTime() {
  // 用new運算子建立一個Date物件,
  const time = new Date()
  const month = time.getMonth()
  const day = time.getDay()
  const date = time.getDate()
  const hours = time.getHours()
  // 讓小時單位為12小時制
  const hoursForClock = hours >= 13 ? hours % 12 : hours
  const minutes = time.getMinutes()
  const seconds = time.getSeconds()
  // 顯示PM或AM
  const ampm = hours >= 12 ? 'PM' : 'AM'
  
  // 以下時針、分針、秒針都帶入scale函式來rotate。
  hourEl.style.transform = `translate(-50%, -100%) rotate(${scale(
    hoursForClock, // 參考的數值
    0,  // 參考數值的變化範圍(最小)
    12, // 參考數值的變化範圍(最大)
    0, // 輸出數值的變化範圍(最小)
    360 // 輸出數值的變化範圍(最大)
  )}deg)`
  
  minuteEl.style.transform = `translate(-50%, -100%) rotate(${scale(
    minutes,
    0,
    60,
    0,
    360
  )}deg)`
  
  secondEl.style.transform = `translate(-50%, -100%) rotate(${scale(
    seconds,
    0,
    60,
    0,
    360
  )}deg)`
  // 讓分鐘單位的顯示為十進位,1 => 01
  timeEl.innerHTML = `${hoursForClock}:${
    minutes < 10 ? `0${minutes}` : minutes
  } ${ampm}`
  
  dateEl.innerHTML = `${days[day]}, ${months[month]} <span class="circle">${date}</span>`
}
setTime()
// 每一秒鐘執行一次setTime函式,啟動時鐘。
setInterval(setTime, 1000)